package org.openintents.shopping.test.test;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.contrib.DrawerActions;
import android.support.test.rule.ActivityTestRule;
import android.support.v7.widget.ActionBarContainer;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Adapter;
import android.widget.AdapterView;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.openintents.shopping.R;
import org.openintents.shopping.ShoppingActivity;
import org.openintents.shopping.library.provider.ShoppingContract;
import org.openintents.shopping.ui.PreferenceActivity;
import org.openintents.util.VersionUtils;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openContextualActionModeOverflowMenu;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.CursorMatchers.withRowString;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
public class ShoppingActivityTest {
public static final String BARCODE_SCANNER_ITEM = "test_barcodescanner_1234";
private static final String TAG = ShoppingActivityTest.class.getSimpleName();
@Rule
public ActivityTestRule rule = new ActivityTestRule<>(ShoppingActivity.class);
private Random random = new Random();
private static Matcher<View> withAdaptedData(final Matcher<String> dataMatcher) {
return new TypeSafeMatcher<View>() {
@Override
public void describeTo(Description description) {
description.appendText("with class name: ");
dataMatcher.describeTo(description);
}
@Override
public boolean matchesSafely(View view) {
if (!(view instanceof AdapterView)) {
return false;
}
@SuppressWarnings("rawtypes")
Adapter adapter = ((AdapterView) view).getAdapter();
for (int i = 0; i < adapter.getCount(); i++) {
if (dataMatcher.matches(adapter.getItem(i))) {
return true;
}
}
return false;
}
};
}
/**
* Perform action of waiting.
*/
public static ViewAction waitFor(final long millis) {
return new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return isRoot();
}
@Override
public String getDescription() {
return "wait during " + millis + " millis.";
}
@Override
public void perform(final UiController uiController, final View view) {
uiController.loopMainThreadForAtLeast(millis);
uiController.loopMainThreadUntilIdle();
}
};
}
private String getAppString(int resId) {
return rule.getActivity().getString(resId);
}
@Before
public void setup() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(rule.getActivity());
SharedPreferences.Editor ed = prefs.edit();
ed.putBoolean(PreferenceActivity.PREFS_HOLO_SEARCH, false);
ed.putBoolean("eula_accepted", true);
ed.putInt("org.openintents.distribution.version_number_check", VersionUtils.getVersionCode(InstrumentationRegistry.getTargetContext()));
ed.commit();
}
@Test
public void testUiAddItem() {
String itemName = "testitem_add_" + random.nextInt(10000);
addItem(itemName);
onData(withRowString(equalTo(ShoppingContract.ContainsFull.ITEM_NAME), is(itemName)))
.inAdapterView(withId(R.id.list_items))
.check(matches(isDisplayed()));
}
@Test
public void testUiDeleteItemPermanently() {
String itemName = "testitem_delete_" + random.nextInt(10000);
addItem(itemName);
longClickOnItem(itemName);
// click delete item
onView(withText(R.string.menu_delete_item)).perform(click());
// Make sure user is asked before this
onView(withText(R.string.delete_item_confirm)).check(matches(isDisplayed()));
// confirm
onView(withText(R.string.delete)).perform(click());
checkHasNotItem(itemName);
}
/**
* Test the add for barcode scanner setting
*/
@Test
public void testSettingAddForBarcode() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(rule.getActivity());
SharedPreferences.Editor ed = prefs.edit();
ed.putBoolean(PreferenceActivity.PREFS_ADDFORBARCODE, false);
ed.apply();
onView(withId(R.id.button_add_item)).perform(longClick());
onView(allOf(withText(getAppString(R.string.menu_pick_items)),
isDescendantOfA(isAssignableFrom(ActionBarContainer.class))))
.check(matches(isDisplayed()));
ed = prefs.edit();
ed.putBoolean(PreferenceActivity.PREFS_ADDFORBARCODE, true);
ed.apply();
onView(withId(R.id.button_add_item)).perform(longClick());
checkHasItem(BARCODE_SCANNER_ITEM);
}
/**
* Test adding items from menu > Barcode scanner test.
*/
@Test
public void testIntentBarcodeScanner() {
// "Scan barcode test" is defined in Manifest of this Test project
String scan_barcode_test = "Scan barcode test";
// Workaround: Open menu manually:
clickOnMenuItem(scan_barcode_test);
// now item should exist:
checkHasItem(BARCODE_SCANNER_ITEM);
}
@Test
public void testMoveToAnotherList() {
String newListName = "New Test List";
String movedItemName = "testitem_move_" + random.nextInt(10000);
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withText(R.string.new_list)).perform(click());
onView(withId(R.id.edittext)).perform(typeText(newListName));
onView(withText(android.R.string.ok)).perform(click());
addItem(movedItemName);
longClickOnItem(movedItemName);
onView(withText(R.string.menu_move_item)).perform(click());
onData(withRowString(equalTo(ShoppingContract.Lists.NAME), is(getAppString(R.string.my_shopping_list)))).perform(click());
// Make sure that the item was moved
checkHasNotItem(movedItemName);
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withText(R.string.my_shopping_list)).perform(click());
checkHasItem(movedItemName);
}
@Test
public void testRenameItem() {
int rndInt = random.nextInt(10000);
String itemName = "not_rename" + rndInt;
String newItemName = "rename" + rndInt;
addItem(itemName);
clickOnItem(itemName);
// wait for dialog to show
onView(isRoot()).perform(waitFor(TimeUnit.MILLISECONDS.toMillis(500)));
onView(withId(R.id.edittext)).perform(replaceText(newItemName));
onView(withText(android.R.string.ok)).perform(click());
checkHasItem(newItemName);
}
private void addItem(String itemName) {
onView(withId(R.id.autocomplete_add_item)).perform(typeText(itemName));
onView(withId(R.id.button_add_item)).perform(click());
hideSoftKeyboard();
}
private void hideSoftKeyboard() {
Activity activity = rule.getActivity();
View view = activity.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
private void longClickOnItem(String itemName) {
onData(withRowString(equalTo(ShoppingContract.ContainsFull.ITEM_NAME), is(itemName)))
.inAdapterView(withId(R.id.list_items))
.onChildView(withText(itemName)).perform(longClick());
}
private void clickOnItem(String itemName) {
onData(withRowString(equalTo(ShoppingContract.ContainsFull.ITEM_NAME), is(itemName)))
.inAdapterView(withId(R.id.list_items)).onChildView(withText(itemName)).perform(click());
}
private void checkHasItem(String itemName) {
onData(hasEntry(equalTo(ShoppingContract.Items.NAME), is(itemName)));
}
private void checkHasNotItem(String itemName) {
onView(withId(R.id.list_items)).check(matches(not(withAdaptedData(equalTo(itemName)))));
}
private void clickOnMenuItem(String text) {
openContextualActionModeOverflowMenu();
onView(withText(text)).perform(click());
}
}